home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / indent / indent.c < prev    next >
C/C++ Source or Header  |  1989-04-06  |  32KB  |  1,105 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * Copyright (c) 1976 Board of Trustees of the University of Illinois.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted
  7.  * provided that this notice is preserved and that due credit is given
  8.  * to the University of California at Berkeley and the University of
  9.  * Illinois at Urbana.  The name of either University may not be used
  10.  * to endorse or promote products derived from this software without
  11.  * specific prior written permission. This software is provided
  12.  * ``as is'' without express or implied warranty.
  13.  */
  14.  
  15. #ifndef lint
  16. char copyright[] =
  17. "@(#) Copyright (c) 1980 Regents of the University of California.\n\
  18. Copyright (c) 1976 Board of Trustees of the University of Illinois.\n\
  19.  All rights reserved.\n";
  20. #endif /* not lint */
  21.  
  22. #ifndef lint
  23. static char sccsid[] = "@(#)indent.c    5.7 (Berkeley) 3/22/88";
  24. #endif /* not lint */
  25.  
  26. /*
  27. NAME:
  28. indent main program
  29.   
  30. FUNCTION:
  31. This is the main program of the indent program.  Indent will take a C
  32. program source and reformat it into a semi-reasonable form.
  33.   
  34. ALGORITHM:
  35. The routine lexi scans tokens and passes them back one at a time to the
  36. main routine.  The subroutine parse takes care of much of the work of
  37. figuring indentation level.  
  38.   
  39. 1) Call lexi
  40. 2) Enter a monster switch statement on the code returned by lexi.  If 
  41. the indentation level for the line yet to be printed should be 
  42. changed, set the variable ps.ind_level.  If the indentation level for
  43. the following line should be changed, set the variable ps.i_l_follow.
  44.  
  45. */
  46. #include "indent_globs.h"
  47. #include "indent_codes.h"
  48.  
  49. char       *in_name = "Standard Input";    /* will always point to name of
  50.                      * input file */
  51. char       *out_name = "Standard Output";    /* will always point to
  52.                          * name of output file */
  53. char        bakfile[32] = "";
  54.  
  55. main(argc, argv)
  56.     int         argc;
  57.     char      **argv;
  58. {
  59.     extern int    found_err;    /* if any error occurred */
  60.  
  61.     int         dec_ind;    /* current indentation for declarations */
  62.     int         di_stack[20];    /* a stack of structure indentation levels */
  63.     int         flushed_nl;    /* used when buffering up comments to
  64.                  * remember that a newline was passed over */
  65.     int         force_nl;    /* when true, code must be broken */
  66.     int         hd_type;    /* used to store type of stmt for if
  67.                  * (...), for (...), etc */
  68.     register int i;        /* local loop counter */
  69.     register int j;        /* local loop counter */
  70.     int         scase;        /* set to true when we see a case, so we
  71.                  * will know what to do with the following
  72.                  * colon */
  73.     int         sp_sw;        /* when true, we are in the expressin of
  74.                  * if(...), while(...), etc. */
  75.     int         squest;        /* when this is positive, we have seen a ?
  76.                  * without the matching : in a <c>?<s>:<s>
  77.                  * construct */
  78.     register char *t_ptr;    /* used for copying tokens */
  79.     int         type_code;    /* the type of token, returned by lexi */
  80.  
  81.     int         last_else = 0;    /* true iff last keyword was an else */
  82.  
  83.  
  84.     /*-----------------------------------------------*\
  85.     |              INITIALIZATION              |
  86.     \*-----------------------------------------------*/
  87.  
  88.  
  89.     ps.p_stack[0] = stmt;    /* this is the parser's stack */
  90.     ps.last_nl = true;        /* this is true if the last thing scanned
  91.                  * was a newline */
  92.     ps.last_token = semicolon;
  93.     combuf[0] = codebuf[0] = labbuf[0] = ' ';    /* set up code, label, and
  94.                          * comment buffers */
  95.     combuf[1] = codebuf[1] = labbuf[1] = '\0';
  96.     s_lab = e_lab = labbuf + 1;
  97.     s_code = e_code = codebuf + 1;
  98.     s_com = e_com = combuf + 1;
  99.  
  100.     buf_ptr = buf_end = in_buffer;
  101.     line_no = 1;
  102.     had_eof = ps.in_decl = ps.decl_on_line = break_comma = false;
  103.     sp_sw = force_nl = false;
  104.     ps.in_or_st = false;
  105.     ps.bl_line = true;
  106.     dec_ind = 0;
  107.     di_stack[ps.dec_nest = 0] = 0;
  108.     ps.want_blank = ps.in_stmt = ps.ind_stmt = false;
  109.  
  110.  
  111.     scase = ps.pcase = false;
  112.     squest = 0;
  113.     sc_end = 0;
  114.     bp_save = 0;
  115.     be_save = 0;
  116.  
  117.     output = 0;
  118.  
  119.  
  120.  
  121.     /*--------------------------------------------------*\
  122.     |   COMMAND LINE SCAN
  123.     \*--------------------------------------------------*/
  124.  
  125.     set_defaults();
  126.  
  127.     /*
  128.      * Unfortunately, we must look for -npro here because the profiles
  129.      * are read before the command line arguments.
  130.      */
  131.     for (i = 1; i < argc; ++i)
  132.     if (strcmp(argv[i], "-npro") == 0)
  133.         break;
  134.     if (i >= argc)
  135.     set_profile();
  136.  
  137.     input = 0;            /* cancel -st if it was in the profiles, */
  138.     output = 0;            /* as it doesn't make any sense there. */
  139.  
  140.     for (i = 1; i < argc; ++i) {
  141.  
  142.     /*
  143.      * look thru args (if any) for changes to defaults 
  144.      */
  145.     if (argv[i][0] != '-') {/* no flag on parameter */
  146.         if (input == 0) {    /* we must have the input file */
  147.         in_name = argv[i];    /* remember name of input file */
  148.         input = fopen(in_name, "r");
  149.         if (input == 0) {    /* check for open error */
  150.             fprintf(stderr, "indent: can't open %s\n", argv[i]);
  151.             exit(1);
  152.         }
  153.         continue;
  154.         } else if (output == 0) {    /* we have the output file */
  155.         out_name = argv[i];    /* remember name of output file */
  156.         if (strcmp(in_name, out_name) == 0) {    /* attempt to overwrite
  157.                              * the file */
  158.             fprintf(stderr, "indent: input and output files must be different\n");
  159.             exit(1);
  160.         }
  161.         output = fopen(out_name, "w");
  162.         if (output == 0) {    /* check for create error */
  163.             fprintf(stderr, "indent: can't create %s\n", argv[i]);
  164.             exit(1);
  165.         }
  166.         continue;
  167.         }
  168.         fprintf(stderr, "indent: unknown parameter: %s\n", argv[i]);
  169.         exit(1);
  170.     } else
  171.         set_option(argv[i]);
  172.  
  173.     }                /* end of for */
  174.     if (input == 0) {
  175.     printf("Usage: indent file [ outfile ] [ options ]\n");
  176.     exit(1);
  177.     }
  178.     if (output == 0)
  179.     if (troff)
  180.         output = stdout;
  181.     else {
  182.         out_name = in_name;
  183.         bakcopy();
  184.     }
  185.  
  186.     /*
  187.      * Adjust parameters that are out of range, or set defaults if
  188.      * no values were specified.
  189.      */
  190.     if (ps.com_ind <= 1)
  191.     ps.com_ind = 2;        /* dont put normal comments before column
  192.                  * 2 */
  193.     if (block_comment_max_col <= 0)
  194.     block_comment_max_col = max_col;
  195.     if (ps.decl_com_ind <= 0)    /* if not specified by user, set this */
  196.     ps.decl_com_ind = ps.ljust_decl ? ps.com_ind - 8 : ps.com_ind;
  197.     if (ps.decl_com_ind <= 1)
  198.     ps.decl_com_ind = 2;
  199.     if (continuation_indent == 0)
  200.     continuation_indent = ps.ind_size;
  201.     fill_buffer();        /* get first batch of stuff into input
  202.                  * buffer */
  203.  
  204.     parse(semicolon);
  205.     {
  206.     register char *p = buf_ptr;
  207.     register    col = 1;
  208.  
  209.     while (1) {
  210.         if (*p == ' ')
  211.         col++;
  212.         else if (*p == '\t')
  213.         col = ((col - 1) & ~7) + 9;
  214.         else
  215.         break;
  216.         p++;
  217.     };
  218.     if (col > ps.ind_size)
  219.         ps.ind_level = ps.i_l_follow = col / ps.ind_size;
  220.     }
  221.     if (troff) {
  222.     register char *p = in_name,
  223.                *beg = in_name;
  224.  
  225.     while (*p)
  226.         if (*p++ == '/')
  227.         beg = p;
  228.     fprintf(output, ".Fn \"%s\"\n", beg);
  229.     }
  230.  
  231.     /*
  232.      * START OF MAIN LOOP 
  233.      */
  234.  
  235.     while (1) {            /* this is the main loop.  it will go
  236.                  * until we reach eof */
  237.     int         is_procname;
  238.  
  239.     type_code = lexi();    /* lexi reads one token.  The actual
  240.                  * characters read are stored in "token".
  241.                  * lexi returns a code indicating the type
  242.                  * of token */
  243.     is_procname = ps.procname[0];
  244.  
  245.     /*
  246.      * The following code moves everything following an if (), while
  247.      * (), else, etc. up to the start of the following stmt to a
  248.      * buffer.  This allows proper handling of both kinds of brace
  249.      * placement. 
  250.      */
  251.  
  252.     flushed_nl = false;
  253.     while (ps.search_brace) {    /* if we scanned an if(), while(),
  254.                      * etc., we might need to copy
  255.                      * stuff into a buffer we must
  256.                      * loop, copying stuff into
  257.                      * save_com, until we find the
  258.                      * start of the stmt which follows
  259.                      * the if, or whatever */
  260.         switch (type_code) {
  261.         case newline:
  262.             ++line_no;
  263.             flushed_nl = true;
  264.         case form_feed:
  265.             break;    /* form feeds and newlines found here will
  266.                  * be ignored */
  267.  
  268.         case lbrace:    /* this is a brace that starts the
  269.                  * compound stmt */
  270.             if (sc_end == 0) {    /* ignore buffering if a comment
  271.                      * wasnt stored up */
  272.             ps.search_brace = false;
  273.             goto check_type;
  274.             }
  275.             if (btype_2) {
  276.             save_com[0] = '{';    /* we either want to put
  277.                          * the brace right after
  278.                          * the if */
  279.             goto sw_buffer;    /* go to common code to get out of
  280.                      * this loop */
  281.             }
  282.         case comment:    /* we have a comment, so we must copy it
  283.                  * into the buffer */
  284.             if (!flushed_nl) {
  285.             if (sc_end == 0) {    /* if this is the first
  286.                          * comment, we must set up
  287.                          * the buffer */
  288.                 save_com[0] = save_com[1] = ' ';
  289.                 sc_end = &(save_com[2]);
  290.             } else {
  291.                 *sc_end++ = '\n';    /* add newline between
  292.                          * comments */
  293.                 *sc_end++ = ' ';
  294.                 --line_no;
  295.             }
  296.             *sc_end++ = '/';    /* copy in start of
  297.                          * comment */
  298.             *sc_end++ = '*';
  299.  
  300.             for (;;) {    /* loop until we get to the end of
  301.                      * the comment */
  302.                 *sc_end = *buf_ptr++;
  303.                 if (buf_ptr >= buf_end)
  304.                 fill_buffer();
  305.  
  306.                 if (*sc_end++ == '*' && *buf_ptr == '/')
  307.                 break;    /* we are at end of comment */
  308.  
  309.                 if (sc_end >= &(save_com[sc_size])) {    /* check for temp buffer
  310.                                      * overflow */
  311.                 diag(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever.");
  312.                 fflush(output);
  313.                 exit(1);
  314.                 }
  315.             }
  316.             *sc_end++ = '/';    /* add ending slash */
  317.             if (++buf_ptr >= buf_end)    /* get past / in buffer */
  318.                 fill_buffer();
  319.             break;
  320.             }
  321.         default:    /* it is the start of a normal statment */
  322.             if (flushed_nl)    /* if we flushed a newline, make
  323.                      * sure it is put back */
  324.             force_nl = true;
  325.             if (type_code == sp_paren && *token == 'i'
  326.             && last_else && ps.else_if
  327.             || type_code == sp_nparen && *token == 'e'
  328.             && e_code != s_code && e_code[-1] == '}')
  329.             force_nl = false;
  330.  
  331.             if (sc_end == 0) {    /* ignore buffering if comment
  332.                      * wasnt saved up */
  333.             ps.search_brace = false;
  334.             goto check_type;
  335.             }
  336.             if (force_nl) {    /* if we should insert a nl here,
  337.                      * put it into the buffer */
  338.             force_nl = false;
  339.             --line_no;    /* this will be re-increased when
  340.                      * the nl is read from the buffer */
  341.             *sc_end++ = '\n';
  342.             *sc_end++ = ' ';
  343.             if (verbose && !flushed_nl)    /* print error msg if
  344.                              * the line was not
  345.                              * already broken */
  346.                 diag(0, "Line broken");
  347.             flushed_nl = false;
  348.             }
  349.             for (t_ptr = token; *t_ptr; ++t_ptr)
  350.             *sc_end++ = *t_ptr;    /* copy token into temp
  351.                          * buffer */
  352.  
  353.         sw_buffer:
  354.             ps.search_brace = false;    /* stop looking for start
  355.                          * of stmt */
  356.             bp_save = buf_ptr;    /* save current input buffer */
  357.             be_save = buf_end;
  358.             buf_ptr = save_com;    /* fix so that subsequent calls to
  359.                      * lexi will take tokens out of
  360.                      * save_com */
  361.             *sc_end++ = ' ';    /* add trailing blank, just in
  362.                      * case */
  363.             buf_end = sc_end;
  364.             sc_end = 0;
  365.             break;
  366.         }            /* end of switch */
  367.         if (type_code != 0)    /* we must make this check, just in case
  368.                  * there was an unexpected EOF */
  369.         type_code = lexi();    /* read another token */
  370.         is_procname = ps.procname[0];
  371.     }            /* end of while (serach_brace) */
  372.     last_else = 0;
  373. check_type:
  374.     if (type_code == 0) {    /* we got eof */
  375.         if (s_lab != e_lab || s_code != e_code
  376.         || s_com != e_com)    /* must dump end of line */
  377.         dump_line();
  378.         if (ps.tos > 1)    /* check for balanced braces */
  379.         diag(1, "Stuff missing from end of file.");
  380.  
  381.         if (verbose) {
  382.         printf("There were %d output lines and %d comments\n",
  383.                ps.out_lines, ps.out_coms);
  384.         printf("(Lines with comments)/(Lines with code): %6.3f\n",
  385.                (1.0 * ps.com_lines) / code_lines);
  386.         }
  387.         fflush(output);
  388.         exit(ps.tos > 1 || found_err);
  389.     }
  390.     if (
  391.         (type_code != comment) &&
  392.         (type_code != newline) &&
  393.         (type_code != preesc) &&
  394.         (type_code != form_feed)) {
  395.         if (
  396.         force_nl
  397.         &&
  398.         (type_code != semicolon) &&
  399.         (
  400.          type_code != lbrace
  401.          ||
  402.          !btype_2
  403.          )) {        /* we should force a broken line here */
  404.         if (verbose && !flushed_nl)
  405.             diag(0, "Line broken");
  406.         flushed_nl = false;
  407.         dump_line();
  408.         ps.want_blank = false;    /* dont insert blank at line start */
  409.         force_nl = false;
  410.         }
  411.         ps.in_stmt = true;    /* turn on flag which causes an extra
  412.                  * level of indentation. this is turned
  413.                  * off by a ; or '}' */
  414.         if (s_com != e_com) {    /* the turkey has embedded a
  415.                      * comment in a line. fix it */
  416.         *e_code++ = ' ';
  417.         for (t_ptr = s_com; *t_ptr; ++t_ptr)
  418.             *e_code++ = *t_ptr;
  419.         *e_code++ = ' ';
  420.         *e_code = '\0';    /* null terminate code sect */
  421.         ps.want_blank = false;
  422.         e_com = s_com;
  423.         }
  424.     } else if (type_code != comment)    /* preserve force_nl thru
  425.                          * a comment */
  426.         force_nl = false;
  427.  
  428.     /*
  429.      * cancel forced newline after newline, form feed, etc 
  430.      */
  431.  
  432.  
  433.  
  434.     /*----------------------------------------------------*\
  435.     |   do switch on type of token scanned
  436.     \*----------------------------------------------------*/
  437.     switch (type_code) {    /* now, decide what to do with the token */
  438.  
  439.         case form_feed:    /* found a form feed in line */
  440.         ps.use_ff = true;    /* a form feed is treated much
  441.                      * like a newline */
  442.         dump_line();
  443.         ps.want_blank = false;
  444.         break;
  445.  
  446.         case newline:
  447.         if (ps.last_token != comma || ps.p_l_follow > 0
  448.             || !ps.leave_comma || !break_comma || s_com != e_com) {
  449.             dump_line();
  450.             ps.want_blank = false;
  451.         }
  452.         ++line_no;    /* keep track of input line number */
  453.         break;
  454.  
  455.         case lparen:    /* got a '(' or '[' */
  456.         ++ps.p_l_follow;/* count parens to make Healy happy */
  457.         if (ps.want_blank && *token != '[' &&
  458.             (ps.last_token != ident || proc_calls_space
  459.              || (ps.its_a_keyword && !ps.sizeof_keyword)))
  460.             *e_code++ = ' ';
  461.         if (ps.in_decl && !ps.block_init)
  462.             if (troff && !ps.dumped_decl_indent) {
  463.             ps.dumped_decl_indent = 1;
  464.             sprintf(e_code, "\\c\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token);
  465.             e_code += strlen(e_code);
  466.             } else {
  467.             while ((e_code - s_code) < dec_ind)
  468.                 *e_code++ = ' ';
  469.             *e_code++ = token[0];
  470.         } else
  471.             *e_code++ = token[0];
  472.         ps.paren_indents[ps.p_l_follow - 1] = e_code - s_code;
  473.         ps.want_blank = false;
  474.         if (ps.in_or_st && *token == '(') {
  475.  
  476.             /*
  477.              * this is a kluge to make sure that declarations will
  478.              * be aligned right if proc decl has an explicit type
  479.              * on it, i.e. "int a(x) {..." 
  480.              */
  481.             parse(semicolon);    /* I said this was a kluge... */
  482.             ps.in_or_st = false;    /* turn off flag for
  483.                          * structure decl or
  484.                          * initialization */
  485.         }
  486.         if (ps.sizeof_keyword) ps.sizeof_mask |= 1<<ps.p_l_follow;
  487.         break;
  488.  
  489.         case rparen:    /* got a ')' or ']' */
  490.         if (ps.cast_mask & (1 << ps.p_l_follow) & ~ps.sizeof_mask) {
  491.             ps.last_u_d = true;
  492.             ps.cast_mask &= (1 << ps.p_l_follow) - 1;
  493.         }
  494.         ps.sizeof_mask &= (1 << ps.p_l_follow) - 1;
  495.         if (--ps.p_l_follow < 0) {
  496.             ps.p_l_follow = 0;
  497.             diag(0, "Extra %c", *token);
  498.         }
  499.         if (e_code == s_code)    /* if the paren starts the line */
  500.             ps.paren_level = ps.p_l_follow;    /* then indent it */
  501.  
  502.         *e_code++ = token[0];
  503.         ps.want_blank = true;
  504.  
  505.         if (sp_sw && (ps.p_l_follow == 0)) {    /* check for end of if
  506.                              * (...), or some such */
  507.             sp_sw = false;
  508.             force_nl = true;    /* must force newline after if */
  509.             ps.last_u_d = true;    /* inform lexi that a following
  510.                      * operator is unary */
  511.             ps.in_stmt = false;    /* dont use stmt continuation
  512.                      * indentation */
  513.  
  514.             parse(hd_type);    /* let parser worry about if, or
  515.                      * whatever */
  516.         }
  517.         ps.search_brace = btype_2;    /* this should insure that
  518.                          * constructs such as
  519.                          * main(){...} and
  520.                          * int[]{...} have their
  521.                          * braces put in the right
  522.                          * place */
  523.         break;
  524.  
  525.         case unary_op:    /* this could be any unary operation */
  526.         if (ps.want_blank)
  527.             *e_code++ = ' ';
  528.  
  529.         if (troff && !ps.dumped_decl_indent && ps.in_decl) {
  530.             sprintf(e_code, "\\c\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token);
  531.             ps.dumped_decl_indent = 1;
  532.             e_code += strlen(e_code);
  533.         } else {
  534.             char       *res = token;
  535.  
  536.             if (ps.in_decl && !ps.block_init) {    /* if this is a unary op
  537.                              * in a declaration, we
  538.                              * should indent this
  539.                              * token */
  540.             for (i = 0; token[i]; ++i);    /* find length of token */
  541.             while ((e_code - s_code) < (dec_ind - i))
  542.                 *e_code++ = ' ';    /* pad it */
  543.             }
  544.             if (troff && token[0] == '-' && token[1] == '>')
  545.             res = "\\(->";
  546.             for (t_ptr = res; *t_ptr; ++t_ptr)
  547.             *e_code++ = *t_ptr;
  548.         }
  549.         ps.want_blank = false;
  550.         break;
  551.  
  552.         case binary_op:    /* any binary operation */
  553.     do_binary:
  554.         if (ps.want_blank)
  555.             *e_code++ = ' ';
  556.         {
  557.             char       *res = token;
  558.  
  559.             if (troff)
  560.             switch (token[0]) {
  561.                 case '<':
  562.                 if (token[1] == '=')
  563.                     res = "\\(<=";
  564.                 break;
  565.                 case '>':
  566.                 if (token[1] == '=')
  567.                     res = "\\(>=";
  568.                 break;
  569.                 case '!':
  570.                 if (token[1] == '=')
  571.                     res = "\\(!=";
  572.                 break;
  573.                 case '|':
  574.                 if (token[1] == '|')
  575.                     res = "\\(br\\(br";
  576.                 else if (token[1] == 0)
  577.                     res = "\\(br";
  578.                 break;
  579.                 case '-':
  580.                 if (token[1] == '>')
  581.                     res = "\\(->";
  582.             }
  583.             for (t_ptr = res; *t_ptr; ++t_ptr)
  584.             *e_code++ = *t_ptr;    /* move the operator */
  585.         }
  586.         ps.want_blank = true;
  587.         break;
  588.  
  589.         case postop:    /* got a trailing ++ or -- */
  590.         *e_code++ = token[0];
  591.         *e_code++ = token[1];
  592.         ps.want_blank = true;
  593.         break;
  594.  
  595.         case question:    /* got a ? */
  596.         squest++;    /* this will be used when a later colon
  597.                  * appears so we can distinguish the
  598.                  * <c>?<n>:<n> construct */
  599.         if (ps.want_blank)
  600.             *e_code++ = ' ';
  601.         *e_code++ = '?';
  602.         ps.want_blank = true;
  603.         break;
  604.  
  605.         case casestmt:    /* got word 'case' or 'default' */
  606.         scase = true;    /* so we can process the later colon
  607.                  * properly */
  608.         goto copy_id;
  609.  
  610.         case colon:    /* got a ':' */
  611.         if (squest > 0) {    /* it is part of the <c>?<n>: <n>
  612.                      * construct */
  613.             --squest;
  614.             if (ps.want_blank)
  615.             *e_code++ = ' ';
  616.             *e_code++ = ':';
  617.             ps.want_blank = true;
  618.             break;
  619.         }
  620.         if (ps.in_decl) {
  621.             *e_code++ = ':';
  622.             ps.want_blank = false;
  623.             break;
  624.         }
  625.         ps.in_stmt = false;    /* seeing a label does not imply
  626.                      * we are in a stmt */
  627.         for (t_ptr = s_code; *t_ptr; ++t_ptr)
  628.             *e_lab++ = *t_ptr;    /* turn everything so far into a
  629.                      * label */
  630.         e_code = s_code;
  631.         *e_lab++ = ':';
  632.         *e_lab++ = ' ';
  633.         *e_lab = '\0';
  634.  
  635.         force_nl = ps.pcase = scase;    /* ps.pcase will be used
  636.                          * by dump_line to decide
  637.                          * how to indent the
  638.                          * label. force_nl will
  639.                          * force a case n: to be
  640.                          * on a line by itself */
  641.         scase = false;
  642.         ps.want_blank = false;
  643.         break;
  644.  
  645.         case semicolon:    /* got a ';' */
  646.         ps.in_or_st = false;    /* we are not in an initialization
  647.                      * or structure declaration */
  648.         scase = false;    /* these will only need resetting in a
  649.                  * error */
  650.         squest = 0;
  651.         if (ps.last_token == rparen)
  652.             ps.in_parameter_declaration = 0;
  653.         ps.cast_mask = 0;
  654.         ps.sizeof_mask = 0;
  655.         ps.block_init = 0;
  656.         ps.just_saw_decl--;
  657.  
  658.         if (ps.in_decl && s_code == e_code && !ps.block_init)
  659.             while ((e_code - s_code) < (dec_ind - 1))
  660.             *e_code++ = ' ';
  661.  
  662.         ps.in_decl = (ps.dec_nest > 0);    /* if we were in a first
  663.                          * level structure
  664.                          * declaration, we arent
  665.                          * any more */
  666.  
  667.         if ((!sp_sw || hd_type != forstmt) && ps.p_l_follow > 0) {
  668.  
  669.             /*
  670.              * This should be true iff there were unbalanced
  671.              * parens in the stmt.  It is a bit complicated,
  672.              * because the semicolon might be in a for stmt 
  673.              */
  674.             diag(1, "Unbalanced parens");
  675.             ps.p_l_follow = 0;
  676.             if (sp_sw) {/* this is a check for a if, while, etc.
  677.                  * with unbalanced parens */
  678.             sp_sw = false;
  679.             parse(hd_type);    /* dont lose the if, or whatever */
  680.             }
  681.         }
  682.         *e_code++ = ';';
  683.         ps.want_blank = true;
  684.         ps.in_stmt = (ps.p_l_follow > 0);    /* we are no longer in
  685.                              * the middle of a stmt */
  686.  
  687.         if (!sp_sw) {    /* if not if for (;;) */
  688.             parse(semicolon);    /* let parser know about end of
  689.                      * stmt */
  690.             force_nl = true;    /* force newline after a end of
  691.                      * stmt */
  692.         }
  693.         break;
  694.  
  695.         case lbrace:    /* got a '{' */
  696.         ps.in_stmt = false;    /* dont indent the {} */
  697.         if (!ps.block_init)
  698.             force_nl = true;    /* force other stuff on same line
  699.                      * as '{' onto new line */
  700.  
  701.         if (s_code != e_code && !ps.block_init) {
  702.             if (!btype_2) {
  703.             dump_line();
  704.             ps.want_blank = false;
  705.             } else if (ps.in_parameter_declaration && !ps.in_or_st) {
  706.             ps.i_l_follow = 0;
  707.             dump_line();
  708.             ps.want_blank = false;
  709.             }
  710.         }
  711.         if (ps.in_parameter_declaration)
  712.             prefix_blankline_requested = 0;
  713.  
  714.         if (ps.p_l_follow > 0) {    /* check for preceding
  715.                          * unbalanced parens */
  716.             diag(1, "Unbalanced parens");
  717.             ps.p_l_follow = 0;
  718.             if (sp_sw) {/* check for unclosed if, for, etc. */
  719.             sp_sw = false;
  720.             parse(hd_type);
  721.             ps.ind_level = ps.i_l_follow;
  722.             }
  723.         }
  724.         if (s_code == e_code)
  725.             ps.ind_stmt = false;    /* dont put extra
  726.                          * indentation on line
  727.                          * with '{' */
  728.         if (ps.in_decl && ps.in_or_st) {    /* this is either a
  729.                              * structure declaration
  730.                              * or an init */
  731.             di_stack[ps.dec_nest++] = dec_ind;
  732.             dec_ind = 0;
  733.         } else {
  734.             ps.decl_on_line = false;    /* we cant be in the
  735.                          * middle of a
  736.                          * declaration, so dont do
  737.                          * special indentation of
  738.                          * comments */
  739.             ps.in_parameter_declaration = 0;
  740.         }
  741.         parse(lbrace);    /* let parser know about this */
  742.         if (ps.want_blank)    /* put a blank before '{' if '{'
  743.                      * is not at start of line */
  744.             *e_code++ = ' ';
  745.         ps.want_blank = false;
  746.         *e_code++ = '{';
  747.         ps.just_saw_decl = 0;
  748.         break;
  749.  
  750.         case rbrace:    /* got a '}' */
  751.         if (ps.p_l_follow) {    /* check for unclosed if, for,
  752.                      * else. */
  753.             diag(1, "Unbalanced parens");
  754.             ps.p_l_follow = 0;
  755.             sp_sw = false;
  756.         }
  757.         ps.just_saw_decl = 0;
  758.         if (s_code != e_code && !ps.block_init) {    /* '}' must be first on
  759.                                  * line */
  760.             if (verbose)
  761.             diag(0, "Line broken");
  762.             dump_line();
  763.         }
  764.         *e_code++ = '}';
  765.         ps.want_blank = true;
  766.         ps.in_stmt = ps.ind_stmt = false;
  767.         if (ps.dec_nest > 0) {    /* we are in multi-level structure
  768.                      * declaration */
  769.             dec_ind = di_stack[--ps.dec_nest];
  770.             if (ps.dec_nest == 0 && !ps.in_parameter_declaration)
  771.             ps.just_saw_decl = 2;
  772.             ps.in_decl = true;
  773.         }
  774.         prefix_blankline_requested = 0;
  775.         parse(rbrace);    /* let parser know about this */
  776.         ps.search_brace = cuddle_else && ps.p_stack[ps.tos] == ifhead && ps.il[ps.tos] >= ps.ind_level;
  777.         if (ps.tos <= 1 && blanklines_after_procs && ps.dec_nest <= 0)
  778.             postfix_blankline_requested = 1;
  779.         break;
  780.  
  781.         case swstmt:    /* got keyword "switch" */
  782.         sp_sw = true;
  783.         hd_type = swstmt;    /* keep this for when we have seen
  784.                      * the expression */
  785.         goto copy_id;    /* go move the token into buffer */
  786.  
  787.         case sp_paren:    /* token is if, while, for */
  788.         sp_sw = true;    /* the interesting stuff is done after the
  789.                  * expression is scanned */
  790.         hd_type = (*token == 'i' ? ifstmt :
  791.                (*token == 'w' ? whilestmt : forstmt));
  792.  
  793.         /*
  794.          * remember the type of header for later use by parser 
  795.          */
  796.         goto copy_id;    /* copy the token into line */
  797.  
  798.         case sp_nparen:    /* got else, do */
  799.         ps.in_stmt = false;
  800.         if (*token == 'e') {
  801.             if (e_code != s_code && (!cuddle_else || e_code[-1] != '}')) {
  802.             if (verbose)
  803.                 diag(0, "Line broken");
  804.             dump_line();    /* make sure this starts a line */
  805.             ps.want_blank = false;
  806.             }
  807.             force_nl = true;    /* also, following stuff must go
  808.                      * onto new line */
  809.             last_else = 1;
  810.             parse(elselit);
  811.         } else {
  812.             if (e_code != s_code) {    /* make sure this starts a
  813.                          * line */
  814.             if (verbose)
  815.                 diag(0, "Line broken");
  816.             dump_line();
  817.             ps.want_blank = false;
  818.             }
  819.             force_nl = true;    /* also, following stuff must go
  820.                      * onto new line */
  821.             last_else = 0;
  822.             parse(dolit);
  823.         }
  824.         goto copy_id;    /* move the token into line */
  825.  
  826.         case decl:        /* we have a declaration type (int,
  827.                  * register, etc.) */
  828.         parse(decl);    /* let parser worry about indentation */
  829.         if (ps.last_token == rparen && ps.tos <= 1)
  830.             ps.in_parameter_declaration = 1;
  831.         if (ps.in_parameter_declaration && ps.indent_parameters && ps.dec_nest == 0) {
  832.             ps.ind_level = ps.i_l_follow = 1;
  833.             ps.ind_stmt = 0;
  834.         }
  835.         ps.in_or_st = true;    /* this might be a structure or
  836.                      * initialization declaration */
  837.         ps.in_decl = ps.decl_on_line = true;
  838.         if ( /* !ps.in_or_st && */ ps.dec_nest <= 0)
  839.             ps.just_saw_decl = 2;
  840.         prefix_blankline_requested = 0;
  841.         for (i = 0; token[i++];);    /* get length of token */
  842.  
  843.         /*
  844.          * dec_ind = e_code - s_code + (ps.decl_indent>i ?
  845.          * ps.decl_indent : i); 
  846.          */
  847.         dec_ind = ps.decl_indent > 0 ? ps.decl_indent : i;
  848.         goto copy_id;
  849.  
  850.         case ident:    /* got an identifier or constant */
  851.         if (ps.in_decl) {    /* if we are in a declaration, we
  852.                      * must indent identifier */
  853.             if (ps.want_blank)
  854.             *e_code++ = ' ';
  855.             ps.want_blank = false;
  856.             if (is_procname == 0 || !procnames_start_line) {
  857.             if (!ps.block_init)
  858.                 if (troff && !ps.dumped_decl_indent) {
  859.                 sprintf(e_code, "\\c\n.De %dp+\200p\n", dec_ind * 7);
  860.                 ps.dumped_decl_indent = 1;
  861.                 e_code += strlen(e_code);
  862.                 } else
  863.                 while ((e_code - s_code) < dec_ind)
  864.                     *e_code++ = ' ';
  865.             } else {
  866.             if (dec_ind && s_code != e_code)
  867.                 dump_line();
  868.             dec_ind = 0;
  869.             ps.want_blank = false;
  870.             }
  871.         } else if (sp_sw && ps.p_l_follow == 0) {
  872.             sp_sw = false;
  873.             force_nl = true;
  874.             ps.last_u_d = true;
  875.             ps.in_stmt = false;
  876.             parse(hd_type);
  877.         }
  878.     copy_id:
  879.         if (ps.want_blank)
  880.             *e_code++ = ' ';
  881.         if (troff && ps.its_a_keyword) {
  882.             *e_code++ = BACKSLASH;
  883.             *e_code++ = 'f';
  884.             *e_code++ = 'B';
  885.         }
  886.         for (t_ptr = token; *t_ptr; ++t_ptr)
  887.             *e_code++ = *t_ptr;
  888.         if (troff && ps.its_a_keyword) {
  889.             *e_code++ = BACKSLASH;
  890.             *e_code++ = 'f';
  891.             *e_code++ = 'R';
  892.         }
  893.         ps.want_blank = true;
  894.         break;
  895.  
  896.         case period:    /* treat a period kind of like a binary
  897.                  * operation */
  898.         *e_code++ = '.';/* move the period into line */
  899.         ps.want_blank = false;    /* dont put a blank after a period */
  900.         break;
  901.  
  902.         case comma:
  903.         ps.want_blank = (s_code != e_code);    /* only put blank after
  904.                              * comma if comma does
  905.                              * not start the line */
  906.         if (ps.in_decl && is_procname == 0 && !ps.block_init)
  907.             while ((e_code - s_code) < (dec_ind - 1))
  908.             *e_code++ = ' ';
  909.  
  910.         *e_code++ = ',';
  911.         if (ps.p_l_follow == 0) {
  912.             ps.block_init = 0;
  913.             if (break_comma && !ps.leave_comma)
  914.             force_nl = true;
  915.         }
  916.         break;
  917.  
  918.         case preesc:    /* got the character '#' */
  919.         if ((s_com != e_com) ||
  920.             (s_lab != e_lab) ||
  921.             (s_code != e_code))
  922.             dump_line();
  923.         *e_lab++ = '#';    /* move whole line to 'label' buffer */
  924.         {
  925.             int         in_comment = 0;
  926.             char       *com_start = 0;
  927.             char        quote = 0;
  928.             char       *com_end = 0;
  929.  
  930.             while (*buf_ptr != '\n' || in_comment) {
  931.             *e_lab = *buf_ptr++;
  932.             if (buf_ptr >= buf_end)
  933.                 fill_buffer();
  934.             switch (*e_lab++) {
  935.                 case BACKSLASH:
  936.                 if (troff)
  937.                     *e_lab++ = BACKSLASH;
  938.                 if (!in_comment) {
  939.                     *e_lab++ = *buf_ptr++;
  940.                     if (buf_ptr >= buf_end)
  941.                     fill_buffer();
  942.                 }
  943.                 break;
  944.                 case '/':
  945.                 if (*buf_ptr == '*' && !in_comment && !quote) {
  946.                     in_comment = 1;
  947.                     *e_lab++ = *buf_ptr++;
  948.                     com_start = e_lab - 2;
  949.                 }
  950.                 break;
  951.                 case '"':
  952.                 if (quote == '"')
  953.                     quote = 0;
  954.                 break;
  955.                 case '\'':
  956.                 if (quote == '\'')
  957.                     quote = 0;
  958.                 break;
  959.                 case '*':
  960.                 if (*buf_ptr == '/' && in_comment) {
  961.                     in_comment = 0;
  962.                     *e_lab++ = *buf_ptr++;
  963.                     com_end = e_lab;
  964.                 }
  965.                 break;
  966.             }
  967.             }
  968.             while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
  969.             e_lab--;
  970.             if (e_lab == com_end && bp_save == 0) {    /* comment on
  971.                                  * preprocessor line */
  972.             if (sc_end == 0)    /* if this is the first
  973.                          * comment, we must set up
  974.                          * the buffer */
  975.                 sc_end = &(save_com[0]);
  976.             else {
  977.                 *sc_end++ = '\n';    /* add newline between
  978.                          * comments */
  979.                 *sc_end++ = ' ';
  980.                 --line_no;
  981.             }
  982.             bcopy(com_start, sc_end, com_end - com_start);
  983.             sc_end += com_end - com_start;
  984.             e_lab = com_start;
  985.             while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
  986.                 e_lab--;
  987.             bp_save = buf_ptr;    /* save current input
  988.                          * buffer */
  989.             be_save = buf_end;
  990.             buf_ptr = save_com;    /* fix so that subsequent
  991.                          * calls to lexi will take
  992.                          * tokens out of save_com */
  993.             *sc_end++ = ' ';    /* add trailing blank,
  994.                          * just in case */
  995.             buf_end = sc_end;
  996.             sc_end = 0;
  997.             }
  998.             *e_lab = '\0';    /* null terminate line */
  999.             ps.pcase = false;
  1000.         }
  1001.         if (strncmp(s_lab, "#if", 3) == 0)
  1002.             if (ifdef_level < sizeof state_stack / sizeof state_stack[0]) {
  1003.             match_state[ifdef_level].tos = -1;
  1004.             state_stack[ifdef_level++] = ps;
  1005.             } else
  1006.             diag(1, "#if stack overflow");
  1007.         else if (strncmp(s_lab, "#else", 5) == 0)
  1008.             if (ifdef_level <= 0)
  1009.             diag(1, "Unmatched #else");
  1010.             else {
  1011.             match_state[ifdef_level - 1] = ps;
  1012.             ps = state_stack[ifdef_level - 1];
  1013.         } else if (strncmp(s_lab, "#endif", 6) == 0)
  1014.             if (ifdef_level <= 0)
  1015.             diag(1, "Unmatched #endif");
  1016.             else {
  1017.             ifdef_level--;
  1018. #ifdef undef
  1019.  
  1020.             /*
  1021.              * This match needs to be more intelligent before
  1022.              * the message is useful 
  1023.              */
  1024.             if (match_state[ifdef_level].tos >= 0
  1025.                 && bcmp(&ps, &match_state[ifdef_level], sizeof ps))
  1026.                 diag(0, "Syntactically inconsistant #ifdef alternatives.");
  1027. #endif
  1028.             }
  1029.         break;        /* subsequent processing of the newline
  1030.                  * character will cause the line to be
  1031.                  * printed */
  1032.  
  1033.         case comment:    /* we have gotten a /*  this is a biggie */
  1034.     proc_comment:
  1035.         if (flushed_nl) {    /* we should force a broken line
  1036.                      * here */
  1037.             flushed_nl = false;
  1038.             dump_line();
  1039.             ps.want_blank = false;    /* dont insert blank at
  1040.                          * line start */
  1041.             force_nl = false;
  1042.         }
  1043.         pr_comment();
  1044.         break;
  1045.     }            /* end of big switch stmt */
  1046.     *e_code = '\0';        /* make sure code section is null
  1047.                  * terminated */
  1048.     if (type_code != comment && type_code != newline && type_code != preesc)
  1049.         ps.last_token = type_code;
  1050.     }                /* end of main while (1) loop */
  1051. };
  1052.  
  1053. /*
  1054.  * copy input file to backup file.  If in_name is /blah/blah/blah/file, then
  1055.  * backup file will be "file.BAK".  Then make the backup file the input and
  1056.  * original input file the output.
  1057.  */
  1058. bakcopy()
  1059. {
  1060.     int         n,
  1061.                 bakchn;
  1062.     char        buff[BUFSIZ];
  1063.     register char *p;
  1064.     char *rindex();
  1065.  
  1066.     if ((p = rindex(in_name, '/')) != NULL)
  1067.     p++;
  1068.     else
  1069.     p = in_name;
  1070.     sprintf(bakfile, "%s.BAK", p);
  1071.  
  1072.     /* copy in_name to backup file */
  1073.     bakchn = creat(bakfile, 0600);
  1074.     if (bakchn < 0) {
  1075.     fprintf(stderr, "indent: can't create backup file \"%s\"\n", bakfile);
  1076.     exit(1);
  1077.     }
  1078.     while ((n = read(fileno(input), buff, sizeof buff)) > 0)
  1079.     if (write(bakchn, buff, n) != n) {
  1080.         fprintf(stderr, "indent: error writing backup file \"%s\"\n",
  1081.         bakfile);
  1082.         exit(1);
  1083.     }
  1084.     if (n < 0) {
  1085.     fprintf(stderr, "indent: error reading input file \"%s\"\n", in_name);
  1086.     exit(1);
  1087.     }
  1088.     close(bakchn);
  1089.     fclose(input);
  1090.  
  1091.     /* re-open backup file as the input file */
  1092.     input = fopen(bakfile, "r");
  1093.     if (input == NULL) {
  1094.     fprintf(stderr, "indent: can't re-open backup file\n");
  1095.     exit(1);
  1096.     }
  1097.     /* now the original input file will be the output */
  1098.     output = fopen(in_name, "w");
  1099.     if (output == NULL) {
  1100.     fprintf(stderr, "indent: can't create %s\n", in_name);
  1101.     unlink(bakfile);
  1102.     exit(1);
  1103.     }
  1104. }
  1105.